#coding=utf-8

import logging
import functools
from google.appengine.api import users
from google.appengine.api import memcache
import datetime
import unicodedata
import tornado.web
from models import *
from utils import page
from lib import markdown
import constants

class BaseController(tornado.web.RequestHandler):
    def get_current_account(self):
        anonymous_user_email = "anonymous@gmail.com"
        user = users.get_current_user()
        if user is None:
            user = users.User(anonymous_user_email)
        account = memcache.get(user.email())
        if account is None:
            account = Account.get_account_for_user(user)
            memcache.set(user.email(), account)
        return account

    def render_response_string(self, template_name, **kwargs):
        user = self.get_current_account()
        sign_in_url = users.create_login_url(self.request.uri)
        sign_out_url = users.create_logout_url(self.request.uri) 
        # Let the templates access the users module to generate login URLs
        return tornado.web.RequestHandler.render_string(
            self, template_name,
            user=user,
            sign_in_url=sign_in_url,
            sign_out_url=sign_out_url,
            **kwargs)
    
    def render_response(self, template_name, **kwargs):
        user = self.get_current_account()
        sign_in_url = users.create_login_url(self.request.uri)
        sign_out_url = users.create_logout_url(self.request.uri) 
        self.render(template_name,
                    user=user,
                    sign_in_url=sign_in_url,
                    sign_out_url=sign_out_url, 
                    **kwargs)
    
    def get_error_html(self, status_code):
        if status_code == 404 or status_code == 403:
            msg = '抱歉，所访问的资源不存在。'
        else:
            msg = '抱歉，所访问的资源不存在。'
        return self.render_string('error.html', error_msg=msg)

### Decorators for request handlers ###
def admin_required(method):
    @functools.wraps(method)
    def wrapper(self, *args, **kwargs):
        if not users.get_current_user():
            if self.request.method == "GET":
                self.redirect(users.create_login_url(self.request.uri))
                return
            raise tornado.web.HTTPError(403)
        elif not users.is_current_user_admin():
            if self.request.method == "GET":
                self.redirect("/")
                return
            raise tornado.web.HTTPError(403)
        else:
            return method(self, *args, **kwargs)
    return wrapper

class HomeController(BaseController):
    def get(self):
        p = int(self.get_argument('p', 1))
        content = None
        if p == 1:
            content = memcache.get(constants.CACHE_KEY_FIRST_PAGE)
        if content is None:
            current_page = Entry.get_page(p, page_size=10)
            tags = Tag.all_entry_tags().fetch(page.DEFAULT_PAGE_SIZE)
            content = self.render_response_string('home.html', page=current_page, tags=tags)
            if p == 1:
                memcache.set(constants.CACHE_KEY_FIRST_PAGE, content)
        self.write(content)

class EntryController(BaseController):
    def get(self, id):
        entry = Entry.get_by_id(long(id))
        if entry is not None:
            return self.render_response("entry.html", entry=entry)
        else:
            raise tornado.web.HTTPError(403)

class RemoveEntryController(BaseController):
    @admin_required
    def get(self, id):
        memcache.delete(constants.CACHE_KEY_FIRST_PAGE)
        memcache.delete(constants.CACHE_KEY_ATOM)
        entry = Entry.get_by_id(long(id))
        if entry is not None:
            entry.remove()
            

class ComposeController(BaseController):
    @admin_required
    def get(self):
        id = self.get_argument("id", None)
        entry = Entry.get_by_id(long(id)) if id else None
        if entry is not None and entry.markdown is None:
            entry.markdown = entry.text
        self.render_response("compose.html", entry=entry)

    @admin_required
    def post(self):
        memcache.delete(constants.CACHE_KEY_FIRST_PAGE)
        memcache.delete(constants.CACHE_KEY_ATOM)
        id = self.get_argument('id', None)
        if id:
            entry = Entry.get_by_id(long(id))
            if entry is None:
                raise tornado.web.HTTPError(404)
            self._bind_entry(entry)
            entry.update()
        else:
            entry = Entry()
            self._bind_entry(entry)
            entry.create()
        self.redirect("/entries/" + str(entry.id))
    
    def _bind_entry(self, entry):
        entry.title          = self.get_argument('title')
        entry.markdown       = self.get_argument("markdown")
        entry.tags_as_string = self.get_argument('tags')
        entry.author         = self.get_current_account().email
        entry.text           = markdown.markdown(self.get_argument("markdown"))

class TagsController(BaseController):
    def get(self):
        tags = Tag.all_entry_tags().fetch(page.DEFAULT_PAGE_SIZE)
        self.render('fragments/tags.html', tags=tags)

class TagEntriesController(BaseController):
    def get(self, tag_kn):
        tag = Tag.get_by_key_name(tag_kn)
        entries = tag.entries if tag is not None else {}
        self.render_response('fragments/tagentries.html', entries=entries, tag=tag)

class ArchiveController(BaseController):
    def get(self):
        entries = Entry.get_feed_entries()
        self.render_response('archive.html', entries=entries)
    
class AtomController(BaseController):
    def get(self):
        content = memcache.get(constants.CACHE_KEY_ATOM)
        if content is None:
            entries = Entry.get_feed_entries()
            if entries and entries[0]:
                last_updated = entries[0].local_put_time
            else:
                last_updated = util.get_local_time(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')
            content = self.render_string('atom.xml', 
                                         entries=entries, 
                                         last_updated=last_updated)
            memcache.set(constants.CACHE_KEY_ATOM, content)
        self.set_header("Content-Type", "application/atom+xml")
        self.write(content)
        
class EntryModule(tornado.web.UIModule):
    def render(self, entry):
        return self.render_string("modules/entry.html", entry=entry, users=users)

class TagCloudModule(tornado.web.UIModule):
    def render(self, tags):
        return self.render_string("modules/tagcloud.html", tags=tags)